import { getCurrentInstance, nextTick, ref, watch } from 'vue'
import * as XLSX from 'xlsx';
import LindadayoService from '@/utils/service';
import {
  ExportDataItem,
  HeaderDisplay,
  TransferReqData,
  TransferResData
} from './types';

export default function(props, { emit }) {
  const {
    proxy
  } = getCurrentInstance();
  // 表格最终要展示的数据
  const data = ref<ExportDataItem[]>(props.exportData);
  // 表格最终要展示的表头数据
  const headerData = ref<HeaderDisplay>(props.headerDisplay);
  // 数据锁
  const requestLock = ref<boolean>(false);
  // 当表头监测有数据变化时，传入赋值
  watch(() => props.headerDisplay, val => {
    headerData.value = val;
  }, {
    deep: true
  })
  // 当展示数据监测有数据变化时，传入赋值
  watch(() => props.exportData, val => {
    data.value = val;
    if (val.length && requestLock.value) {
      methods.exportTransfer();
      requestLock.value = false;
    }
  }, {
    deep: true
  })
  const methods = {
    /**
     * 导出前置控制
     */
    async exportControl() {
      if (props.apiConfig) {
        const res = await methods.getExcelList();
        res && methods.exportTransfer();
      } else {
        emit('getData');
        requestLock.value = true;
      }
    },
    /**
     * 数据导出成excel
     */
    exportTransfer() {
      console.time('导出excel耗时：');
      nextTick(() => {
        const newData = [headerData.value, ...data.value] // 封装组合后的数据
        const headProp = props.headerConfig.map(item => item.prop) // 头部属性数组
        // 把json转为worksheet对象 后续用这种方法
        const wb = XLSX.utils.json_to_sheet(newData, { header: headProp, skipHeader: true })
        // 列宽度数组
        let widthList = [];
        // 默认列宽度
        const defaultWidth = 130;
        // headerDisplay参数个数
        const headerDisplayCount = Object.keys(headerData.value).length;
        // 如果有headerConfig属性，则使用headerConfig
        if (props.headerConfig.length) {
          widthList = props.headerConfig.map(item => item.width ? Number(item.width) : defaultWidth);
        // 否则使用headerData的数量来依次赋值默认宽度
        } else {
          widthList = Array.from({ length: headerDisplayCount }).map(_item => defaultWidth);
        }
        wb['!cols'] = [] // 先初始化列数组配置
        for (let i = 0; i < widthList.length; i++) {
          wb['!cols'][i] = {
            wpx: widthList[i]
          }
        }
        // 样式的文档地址
        // https://www.npmjs.com/package/xlsx-style
        for (const key in wb) {
          if (key.indexOf('!') === -1) { // 非excel配置类，带!都是配置类，这里对非配置类进行样式修改
            wb[key].s = {
              font: { // 字体设置
                sz: 13,
                bold: false,
                color: {
                  rgb: '000000'
                }
              },
              alignment: { // 文字居中
                horizontal: 'center',
                vertical: 'center',
                wrapText: 1 // 换行
              },
              border: { // 设置边框
                top: { style: 'thin' },
                bottom: { style: 'thin' },
                left: { style: 'thin' },
                right: { style: 'thin' }
              }
            }
          }
        }
        const filedata = methods.sheet2blob(wb)
        methods.openDownloadDialog(filedata, props.fileName)
      })
    },
    /**
     * 将一个sheet转成最终的excel文件的blob对象，然后利用URL.createObjectURL下载
     * @param sheet excel对象
     * @param sheetName
     * @returns
     */
    sheet2blob(sheet, sheetName?: string) {
      const s2ab = (s) => {
        const buf = new ArrayBuffer(s.length);
        const view = new Uint8Array(buf);
        for (let i = 0; i < s.length; ++i) {
          view[i] = s.charCodeAt(i) & 0xFF;
        }
        return buf;
      }
      sheetName = sheetName || 'sheet1';
      const workbook = {
        SheetNames: [sheetName],
        Sheets: {}
      };
      workbook.Sheets[sheetName] = sheet; // 生成excel的配置项
      const wopts = {
        bookType: 'xlsx', // 要生成的文件类型
        bookSST: false, // 是否生成Shared String Table，官方解释是，如果开启生成速度会下降，但在低版本IOS设备上有更好的兼容性
        type: 'binary'
      };
      const wbout = XLSX.write(workbook, wopts as any);
      const blob = new Blob([s2ab(wbout)], { // 字符串转ArrayBuffer
        type: 'application/octet-stream'
      });
      console.log('生成二进制流数据');
      return blob;
    },
    /**
     * 创建excel地址并下载到本地
     * @param url 文件blob二进制路径
     * @param saveName 文件名
     */
    openDownloadDialog(url, saveName) {
      if (typeof url === 'object' && url instanceof Blob) {
        url = URL.createObjectURL(url); // 创建blob地址
      }
      console.log('开始导出');
      const aLink = document.createElement('a');
      aLink.href = url;
      aLink.download = `${saveName}.xlsx`; // HTML5新增的属性，指定保存文件名
      let event;
      if (window.MouseEvent) {
        event = new MouseEvent('click');
      } else {
        event = document.createEvent('MouseEvents'); // 事件抛出
        event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
      }
      aLink.dispatchEvent(event); // 事件派发
      console.timeEnd('导出excel耗时：');
    },
    /**
     * 传入接口地址，获取导入的数据
     * @returns
     */
    async getExcelList() {
      const defaultOptions = {
        headers: {
          'Content-Type': 'application/json'
        }
      }
      const {
        url,
        method,
        options,
        params
      } = props.apiConfig;
      const apis = new LindadayoService<TransferResData, TransferReqData>({
        getExcelList: {
          url,
          method: method ?? 'get',
          options: options ?? defaultOptions
        }
      })
      const res = await apis.getExcelList(params);
      if (res.errcode !== 0) {
        proxy.$message.error(res.errmsg);
        return false;
      }
      data.value = res.data;
      return true;
    }
  }
  return {
    methods,
    data
  }
}

